
/*
 * Copyright (C) 2013-2016 Sergej Shafarenka, halfbit.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file kt in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.halfbit.pinnedsection;

import de.halfbit.pinnedsection.library.ResourceTable;
import ohos.agp.components.AttrSet;
import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.ListContainer;
import ohos.agp.components.Text;
import ohos.agp.utils.Color;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;

import java.util.Collections;
import java.util.List;
import java.util.stream.IntStream;

/**
 * Pinned SectionListView extends DirectionalLayout and implemented as component of Sticky header and list.
 *
 * @author rwx1012962
 * @since 2021-01-27
 */
public class PinnedSectionListView extends DirectionalLayout implements Component.ScrolledListener {
    private static final int HEADER_PADDING = 10;

    private static final int TEXT_SIZE = 50;

    private Context context;

    private IClickedListener clickedListener;

    private List<PinnedSection> mDataList;

    private Text mPinnedHeader;

    private ListContainer mListContainer;

    private int mListCount = 0;

    private int mItemCount = 0;

    private int mIncrement = 0;

    private boolean mIsRandomColorHeader = true;

    /**
     * Default Constructor
     *
     * @param context {@link Context }
     */
    public PinnedSectionListView(Context context) {
        super(context);
        this.context = context;
        initView();
    }

    /**
     * This constructor is used to create instance to PinnedSectionListView class.
     *
     * @param context context
     * @param attrSet {@link AttrSet}
     */
    public PinnedSectionListView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        this.context = context;
        initView();
    }

    /**
     * Constructor
     *
     * @param context {@link Context}
     * @param attrSet {@link AttrSet}
     * @param styleName {@link String}
     */
    public PinnedSectionListView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        this.context = context;
        initView();
    }

    /**
     * Creates the dynamic list view and header. These component added to super class layout.
     */
    private void initView() {
        ComponentContainer.LayoutConfig containerParam = new ComponentContainer.LayoutConfig();
        containerParam.width = ComponentContainer.LayoutConfig.MATCH_PARENT;
        containerParam.height = ComponentContainer.LayoutConfig.MATCH_PARENT;
        setLayoutConfig(containerParam);
        setOrientation(VERTICAL);

        mPinnedHeader = new Text(context);
        ComponentContainer.LayoutConfig layoutParams = new ComponentContainer.LayoutConfig();
        layoutParams.width = ComponentContainer.LayoutConfig.MATCH_PARENT;
        layoutParams.height = ComponentContainer.LayoutConfig.MATCH_CONTENT;
        mPinnedHeader.setTextSize(TEXT_SIZE);
        mPinnedHeader.setPadding(HEADER_PADDING, HEADER_PADDING, HEADER_PADDING, HEADER_PADDING);
        mPinnedHeader.setTextAlignment(TextAlignment.VERTICAL_CENTER);
        mPinnedHeader.setTextColor(Color.WHITE);
        mPinnedHeader.setBackground(StyleElement.getStyleElement(Color.BLUE.getValue()));
        mPinnedHeader.setClickedListener(component -> clickedListener.onStickyHeaderClicked(component));

        mListContainer = new ListContainer(context);
        ComponentContainer.LayoutConfig listParams = new ComponentContainer.LayoutConfig();
        listParams.width = ComponentContainer.LayoutConfig.MATCH_PARENT;
        listParams.height = ComponentContainer.LayoutConfig.MATCH_PARENT;
        mListContainer.setScrolledListener(this);

        mListContainer.setBackground(StyleElement.getStyleElement(Color.WHITE.getValue()));

        addComponent(mPinnedHeader, layoutParams);
        addComponent(mListContainer, listParams);
    }

    public void setHeaderSticky(boolean value) {
        mPinnedHeader.setVisibility(value ? VISIBLE : HIDE);
    }

    public void setRandomColorHeader(boolean value){
        mIsRandomColorHeader = value;
    }

    /**
     * overrided method onContentScrolled.
     *
     * @param component
     * @param i
     * @param i1
     * @param i2
     * @param i3
     */
    @Override
    public void onContentScrolled(Component component, int i, int i1, int i2, int i3) {
        int position = mListContainer.getFirstVisibleItemPosition();
        mPinnedHeader.setText(mDataList.get(position).getText().substring(0, 1));
        if(mDataList.get(position).isHeader()) {
            mPinnedHeader.setBackground(mListContainer.getComponentAt(position).getBackgroundElement());
        }
    }

    /**
     * method setDataItems is for setting datalist to lost view. Also second argument #isRandomColorHeader
     * is used to decide whether rendom color or default color for header.
     *
     * @param dataList {@link DataAdapter}
     * @param footerText {@link String}
     */
    public void setDataItems(List<PinnedSection> dataList, String footerText) {
        mListCount = dataList.size();
        mDataList = dataList;
        Collections.sort(mDataList);
        IntStream.range('A', 'a').forEach(i -> {
            int count = filter(mDataList, String.valueOf((char) i));
            if (count > 0) {
                PinnedSection header = new PinnedSection();
                header.setText(String.valueOf((char) i));
                header.setHeader(true);
                mDataList.add(mItemCount + mIncrement, header);
                mItemCount += count;
                mIncrement++;
            }
        });
        /*if ((mDataList.size() - mItemCount - mIncrement) > 0) {
            PinnedSection header = new PinnedSection();
            header.setText("123");
            header.setHeader(true);
            mDataList.add(mItemCount + mIncrement, header);
        }*/
        if(footerText != null && !footerText.isEmpty()) {
            PinnedSection footer = new PinnedSection();
            footer.setText(footerText);
            footer.setFooter(true);
            mDataList.add(mDataList.size(), footer);
        }
        mPinnedHeader.setText(mDataList.get(0).getText());
        mDataList.remove(0);

        DataAdapter adapter = new DataAdapter(context, mDataList, mIsRandomColorHeader);
        if (mListContainer != null) {
            mListContainer.setItemProvider(adapter);
        }

        mListContainer.setItemClickedListener(
            (listContainer, component, position, l) -> clickedListener.onItemClicked(listContainer, component, position,
                l));
    }

    /**
     * Register click listner.
     *
     * @param listener {@link IClickedListener}
     */
    public void registerClickListner(IClickedListener listener) {
        clickedListener = listener;
    }

    /**
     * UnRegister click listner.
     */
    public void unregisterClickListner() {
        clickedListener = null;
    }

    /**
     * StyleElement
     *
     * @author rwx1012962
     * @since 2021-01-27
     */
    public class DataAdapter extends BaseItemProvider {
        private List<PinnedSection> list;

        private boolean isRandomColorHeader;

        private Context context;

        /**
         * Constructor
         *
         * @param context {@link Context}
         * @param list @link List}
         * @param isRandomColorHeader @link Color}
         */
        public DataAdapter(Context context, List<PinnedSection> list, boolean isRandomColorHeader) {
            this.list = list;
            this.context = context;
            this.isRandomColorHeader = isRandomColorHeader;
        }

        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public PinnedSection getItem(int i) {
            return list.get(i);
        }

        @Override
        public long getItemId(int index) {
            return index;
        }

        @Override
        public Component getComponent(int position, Component component, ComponentContainer componentContainer) {
            Component convertView = component;
            Text title;
            if (getItem(position).getFooter()) {
                convertView = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_footer_item, null, false);
                title = (Text) convertView.findComponentById(ResourceTable.Id_footer_title);
                if (isRandomColorHeader) {
                    convertView.setBackground(StyleElement.getRandomColor());
                } else {
                    convertView.setBackground(StyleElement.getStyleElement(Color.GREEN.getValue()));
                }
            } else if (getItem(position).isHeader()) {
                convertView = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_header_item, null, false);
                title = (Text) convertView.findComponentById(ResourceTable.Id_header_title);
                if (isRandomColorHeader) {
                    convertView.setBackground(StyleElement.getRandomColor());
                } else {
                    convertView.setBackground(StyleElement.getStyleElement(Color.BLUE.getValue()));
                }
            } else {
                convertView = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_list_item, null, false);
                title = (Text) convertView.findComponentById(ResourceTable.Id_text_data);
            }
            title.setText(list.get(position).getText());
            return convertView;
        }
    }

    /**
     * method filter is used to find count of list items which are starts with #prefix
     *
     * @param source
     * @param prefix
     * @return int count
     */
    private int filter(final List<PinnedSection> source, final String prefix) {
        int count = 0;

        for (int index = 0; index < source.size(); index++) {
            if (source.get(index).getText().startsWith(prefix)) {
                count++;
            }
        }
        return count;
    }
}
